package util.methods;

import java.awt.*;

import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;

import java.awt.geom.Rectangle2D;
import java.lang.reflect.Method;
import java.net.URL;

public class UIHelpers 
{ 
	static public JLabel createCenteredLabel ( String str )
	{
		JLabel label = new JLabel ( str );
		label.setAlignmentX( Component.CENTER_ALIGNMENT );
		return label;
	}
	
    public static void setFrameWaitCursor ( Container c )
    {
        // Set the wait cursor:
        Frame parent = findParentFrame( c );
        if ( parent != null )
            parent.setCursor( Cursor.getPredefinedCursor( Cursor.WAIT_CURSOR ) );
    }

    public static void clearFrameCursor ( Container c )
    {
        // Clear the cursor
        Frame parent = findParentFrame( c );
        if ( parent != null )
            parent.setCursor( null );
    }   
    
    // Return the view port dimension of the input contain in
    // the containers coordinate frames
    static public Rectangle getViewPortRect ( Container c )
    {
        int nDX = 0;
        int nDY = 0;
        Container parent = c;
        
        do 
        { 
            if ( parent instanceof JViewport ) 
            {   
                return new Rectangle ( -nDX, -nDY, parent.getWidth(), parent.getHeight() );
            }
            
            // Accumulate the conversion factor
            nDX += parent.getX();
            nDY += parent.getY();
            
            // Get the parent's parent for next time around
            parent = parent.getParent();
            
        } while ( parent != null );
        
        return null; // Contain is not installed in a JViewport
    }
    
    // scroll the input container to the center of its scroll pane (or two
    // nested scroll panes if bDoubleScrollers is true)
    static public void scrollToCenter ( Container c, boolean bDoubleScrollers )
    { 
        Rectangle rect = new Rectangle ( 0, 0, c.getWidth(), c.getHeight() );
        Container parent = c;
        int nScrolls = 0;
        
        do 
        { 
            if ( parent instanceof JViewport ) 
            {
                JViewport thePort = (JViewport)parent;
                JScrollPane theScroller = (JScrollPane)thePort.getParent();
                
                // Calulate the centered position
                Point pntBefore = new Point ( thePort.getViewPosition() );
                Rectangle scrollTo = new Rectangle (  thePort.getViewRect ( ) );
                if ( theScroller.getHorizontalScrollBarPolicy() != JScrollPane.HORIZONTAL_SCROLLBAR_NEVER )
                    scrollTo.x = (int) ( rect.getCenterX() - scrollTo.getWidth() / 2 );
                if ( theScroller.getVerticalScrollBarPolicy() != JScrollPane.VERTICAL_SCROLLBAR_NEVER )         
                    scrollTo.y = (int) ( rect.getCenterY() - scrollTo.getHeight() / 2 );
                
                // Scroll
                thePort.scrollRectToVisible ( scrollTo );
                ++nScrolls;
                if ( nScrolls == 2 || !bDoubleScrollers )
                    break; // Done
            
                // Adjust for the scroll
                Point pntAfter = thePort.getViewPosition();
                rect.x -= pntAfter.getX() - pntBefore.getX();
                rect.y -= pntAfter.getY() - pntBefore.getY();
            }
            
            // Convert to the parent's coordiates
            rect.x += parent.getX();
            rect.y += parent.getY();
            
            // Get the parent's parent for next time around
            parent = parent.getParent();
            
        } while ( parent != null );

    } 
    
    // For some reason java returns text dimensions in real numbers, but
    // the often chops of the top row pixels.  This will round up the
    // width, height values so as to avoid this nonsense.
    static public void roundUpRect ( Rectangle2D rect )
    {
        rect.setRect( rect.getX(), rect.getY(), Math.ceil( rect.getWidth() ), Math.ceil( rect.getHeight() ) );
    }
    
    // Find the parent frame for the input container
    static public Frame findParentFrame( Container c )
    { 
        Frame parent = null;
        while(c != null){ 
          if (c instanceof Frame) 
            parent = (Frame)c; 
          c = c.getParent(); 
        } 
        return parent; 
    } 
    
    // Creates a JScrollPane using the input client and attempts
    // to set its preferred size to optimal values.  
    // The JScrollPane's preferred size is set using the dimensions from the client't
    // preferred size, unless they are larger than the screen.
    // In this case it sets the dimension to 90% of the screen and adjusts
    // the other for the added length/width of the scroll bar.
    // This seems to work well, if all of the sub-panes
    // are installed in "scrollableClient" before the call.  Then call pack on
    // the Dialog/Frame before you open it.
    static public JScrollPane createAdjustedJScrollPane ( Component scrollableClient )
    {
        JScrollPane scroller = new JScrollPane ( scrollableClient );
        scroller.setHorizontalScrollBarPolicy( JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED );
        scroller.setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED );
        
        double dScreenFill = 0.9;
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 
        Dimension prefSize = scrollableClient.getPreferredSize();
        
        int nScrollDim = (int)scroller.getHorizontalScrollBar().getPreferredSize().getHeight();
        boolean bVertScroll = false;
        boolean bHorzScroll = false;
        
        int nNewWidth = (int)prefSize.getWidth();
        int nNewHeight = (int)prefSize.getHeight();
        
        if ( (screenSize.getHeight() + nScrollDim) <= nNewHeight )
        {
            bVertScroll = true;
            nNewHeight = (int) (screenSize.getHeight() * dScreenFill );
        }
            
        if ( (screenSize.getWidth() + nScrollDim ) <= nNewWidth )
        {
            bHorzScroll = true;
            nNewWidth = (int) (screenSize.getWidth() * dScreenFill );
        }
        
        // Factor in the scroll bars, since Java isn't nice enough to do 
        // this
        if ( bVertScroll )
            nNewWidth += nScrollDim;
        if ( bHorzScroll )
            nNewHeight += nScrollDim;
        
        // seems consistently a couple pixels off for some reason
        nNewWidth += 3;
        nNewHeight += 3;        
        
        // Set the new preferred size
        prefSize.setSize( nNewWidth, nNewHeight );
        scroller.setPreferredSize( prefSize );
        return scroller;
    }
    
    static public void setMaxToPreferred ( JComponent thing )
    {
        thing.setMaximumSize( thing.getPreferredSize() );
    }
    
    static public void setPreferredToInfiniteWidth ( JComponent thing )
    {
        thing.setPreferredSize( new Dimension ( Integer.MAX_VALUE, (int)thing.getPreferredSize().getHeight() ) );
    }
 
    static public void setPreferredToInfinite ( JComponent thing )
    {
        thing.setPreferredSize( new Dimension ( Integer.MAX_VALUE, Integer.MAX_VALUE ) );
    }
    
    static public void setScrollIncrements ( JScrollPane scrollBar )
    {
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 
        scrollBar.getHorizontalScrollBar().setUnitIncrement( (int)(screenSize.getWidth() / 10) );       
        scrollBar.getVerticalScrollBar().setUnitIncrement( (int)(screenSize.getHeight() / 10) );        
    }
    
    
    //   centers the input window on the screen
    static public void centerScreen( Window win ) 
    {
          Dimension dim = win.getToolkit().getScreenSize();
          Rectangle abounds = win.getBounds();
          win.setLocation((dim.width - abounds.width) / 2,
              (dim.height - abounds.height) / 2);
    }

  
    //   centers the input window relative to its parent
    static public void centerParent ( Window win ) 
    {
          int x;
          int y;
        
          // Find out our parent 
          Container myParent = win.getParent();
          
          // Center using the parent if it's visible, just use the
          // screen otherwise
          if ( myParent.getWidth() > 0 && myParent.getHeight() > 0 )
          { 
                Point topLeft = myParent.getLocationOnScreen();
                Dimension parentSize = myParent.getSize();
            
                Dimension mySize = win.getSize();
            
                if (parentSize.width > mySize.width) 
                    x = ((parentSize.width - mySize.width)/2) + topLeft.x;
                else 
                    x = topLeft.x;
               
                if (parentSize.height > mySize.height) 
                    y = ((parentSize.height - mySize.height)/2) + topLeft.y;
                else 
                    y = topLeft.y;
               
                win.setLocation (x, y);
          }
          else
                centerScreen ( win );
    }  
    
    static public void addToGridBag ( Component toAdd, GridBagConstraints constraints, GridBagLayout layout, Container parent )
    {
    	layout.setConstraints( toAdd, constraints );
    	parent.add( toAdd );
    }
    
	// These work good with a box layout, but not a grid bag layout....
	static public JPanel createHorzBoxBar ( int nHorzSpace, Component comp1, Component comp2 )
	{
		Component [] bar = new Component [2];
		bar [0] = comp1;
		bar [1] = comp2;
		return createHorzBoxBar ( nHorzSpace, bar );
	}

	static public JPanel createHorzBoxBar ( int nHorzSpace, Component comp1, Component comp2, Component comp3 )
	{
		Component [] bar = new Component [3];
		bar [0] = comp1;
		bar [1] = comp2;
		bar [2] = comp3;
		return createHorzBoxBar ( nHorzSpace, bar );		
	}

	static public JPanel createHorzBoxBar ( int nHorzSpace, 
											Component comp1, 
											Component comp2, 
											Component comp3,
											Component comp4 )
	{
		Component [] bar = new Component [4];
		bar [0] = comp1;
		bar [1] = comp2;
		bar [2] = comp3;
		bar [3] = comp4;
		return createHorzBoxBar ( nHorzSpace, bar );		
	}
	
	static public JPanel createHorzBoxBar ( int nHorzSpace, 
											Component comp1, 
											Component comp2, 
											Component comp3,
											Component comp4,
											Component comp5 )
	{
		Component [] bar = new Component [5];
		bar [0] = comp1;
		bar [1] = comp2;
		bar [2] = comp3;
		bar [3] = comp4;
		bar [4] = comp5;
		return createHorzBoxBar ( nHorzSpace, bar );		
	}
	
	static public JPanel createHorzBoxBar ( int nHorzSpace, 
											Component comp1, 
											Component comp2, 
											Component comp3,
											Component comp4,
											Component comp5,
											Component comp6 )
	{
		Component [] bar = new Component [6];
		bar [0] = comp1;
		bar [1] = comp2;
		bar [2] = comp3;
		bar [3] = comp4;
		bar [4] = comp5;
		bar [5] = comp6;
		return createHorzBoxBar ( nHorzSpace, bar );		
	}
	
	static public JPanel createHorzBoxBar ( int nHorzSpace, Component[] compArray )
	{		
		JPanel panel = new JPanel ();
		panel.setLayout( new BoxLayout ( panel, BoxLayout.X_AXIS ) );
		for ( int i = 0; i < compArray.length; ++i )
		{
			panel.add( compArray[i] );
			if ( ( i + 1 ) < compArray.length )
				panel.add( Box.createHorizontalStrut( nHorzSpace ) );	
		}
		setupHorzBoxBar ( panel );
		return panel;
	}
	
	// Sets up the component to be left align and to expand horizontally, but not
	// vertically.  This works good with a box layout, but not a grid bag...
	static public void setupHorzBoxBar ( JComponent comp )
	{
		int nHeight = (int)comp.getPreferredSize().getHeight();
		comp.setAlignmentX ( Component.LEFT_ALIGNMENT );
		comp.setPreferredSize( new Dimension ( Integer.MAX_VALUE, nHeight ) );
		comp.setMaximumSize( new Dimension ( Integer.MAX_VALUE, nHeight ) );
	}
	
	// These work good with a grid bag layout, but not a box layout....
	static public JPanel createHorzGridBar ( int nHorzSpace, Component comp1, Component comp2 )
	{
		Component [] bar = new Component [2];
		bar [0] = comp1;
		bar [1] = comp2;
		return createHorzGridBar ( nHorzSpace, bar );
	}

	static public JPanel createHorzGridBar ( int nHorzSpace, Component comp1, Component comp2, Component comp3 )
	{
		Component [] bar = new Component [3];
		bar [0] = comp1;
		bar [1] = comp2;
		bar [2] = comp3;
		return createHorzGridBar ( nHorzSpace, bar );		
	}

	static public JPanel createHorzGridBar ( int nHorzSpace, 
											Component comp1, 
											Component comp2, 
											Component comp3,
											Component comp4 )
	{
		Component [] bar = new Component [4];
		bar [0] = comp1;
		bar [1] = comp2;
		bar [2] = comp3;
		bar [3] = comp4;
		return createHorzGridBar ( nHorzSpace, bar );		
	}
	
	static public JPanel createHorzGridBar ( int nHorzSpace, 
											Component comp1, 
											Component comp2, 
											Component comp3,
											Component comp4,
											Component comp5 )
	{
		Component [] bar = new Component [5];
		bar [0] = comp1;
		bar [1] = comp2;
		bar [2] = comp3;
		bar [3] = comp4;
		bar [4] = comp5;
		return createHorzGridBar ( nHorzSpace, bar );		
	}
	
	static public JPanel createHorzGridBar ( int nHorzSpace, 
											Component comp1, 
											Component comp2, 
											Component comp3,
											Component comp4,
											Component comp5,
											Component comp6 )
	{
		Component [] bar = new Component [6];
		bar [0] = comp1;
		bar [1] = comp2;
		bar [2] = comp3;
		bar [3] = comp4;
		bar [4] = comp5;
		bar [5] = comp6;
		return createHorzGridBar ( nHorzSpace, bar );		
	}
	
	static public JPanel createHorzGridBar ( int nHorzSpace, Component[] compArray )
	{		
		JPanel panel = new JPanel ();
		panel.setLayout( new BoxLayout ( panel, BoxLayout.X_AXIS ) );
		for ( int i = 0; i < compArray.length; ++i )
		{
			panel.add( compArray[i] );
			if ( ( i + 1 ) < compArray.length )
				panel.add( Box.createHorizontalStrut( nHorzSpace ) );	
		}
		return panel;
	}
	
	static public JPanel createVertBar (  )
	{
		JPanel panel = new JPanel ();
		panel.setLayout( new BoxLayout ( panel, BoxLayout.Y_AXIS ) );
		return panel;
	}
	
	static public JPanel createVertBar ( int nSpace, Component comp1, Component comp2 )
	{
		Component [] bar = new Component [2];
		bar [0] = comp1;
		bar [1] = comp2;
		return createVertBar ( nSpace, bar );
	}

	static public JPanel createVertBar ( int nSpace, Component comp1, Component comp2, Component comp3 )
	{
		Component [] bar = new Component [3];
		bar [0] = comp1;
		bar [1] = comp2;
		bar [2] = comp3;
		return createVertBar ( nSpace, bar );		
	}
	
	static public JPanel createVertBar ( int nSpace, Component[] compArray )
	{		
		JPanel panel = new JPanel ();
		panel.setLayout( new BoxLayout ( panel, BoxLayout.Y_AXIS ) );
		
		for ( int i = 0; i < compArray.length; ++i )
		{
			panel.add( compArray[i] );
			if ( ( i + 1 ) < compArray.length )
				panel.add( Box.createVerticalStrut( nSpace ) );	
		}
		return panel;
	}
	
	static public JPanel createFlowBar ( Component comp1 )
	{
		Component [] bar = new Component [1];
		bar [0] = comp1;
		return createFlowBar ( bar );
	}
	
	static public JPanel createFlowBar ( Component comp1, Component comp2 )
	{
		Component [] bar = new Component [2];
		bar [0] = comp1;
		bar [1] = comp2;
		return createFlowBar ( bar );
	}
	
	static public JPanel createFlowBar ( Component[] compArray )
	{		
		JPanel panel = new JPanel ( new FlowLayout () );
		for ( int i = 0; i < compArray.length; ++i )
		{
			panel.add( compArray[i] );
		}
		return panel;
	}
	
	static public JComponent createOptionGroupBox ( String strTitle, int INSET )
	{
		JComponent thePanel = Box.createVerticalBox();
		Border innerBorder = BorderFactory.createEmptyBorder( INSET, INSET, INSET, INSET ) ;
		Border outerBorder = BorderFactory.createTitledBorder( strTitle );		
		CompoundBorder wholeBorder = BorderFactory.createCompoundBorder( outerBorder, innerBorder );
		thePanel.setBorder ( wholeBorder );
		thePanel.add( Box.createHorizontalGlue() );
		return thePanel;
	}
	
	public static boolean tryOpenURL ( URL theLink )
    {
    	// Show document with applet if we have one
		if ( theApplet != null )
		{
			theApplet.getAppletContext().showDocument( theLink, "_blank" );
			return true;
		}
		
		// Otherwise unless we become a web start application
    	// we are stuck with the below...  I copied this from: http://www.centerkey.com/java/browser/.
    	String osName = System.getProperty("os.name"); 
    	try 
    	{ 
    		if (osName.startsWith("Mac OS")) 
    		{ 
    			Class<?> fileMgr = Class.forName("com.apple.eio.FileManager"); 
    			Method openURL = fileMgr.getDeclaredMethod("openURL", new Class[] {String.class}); 
    			openURL.invoke(null, new Object[] {theLink}); 
    			return true;
    		} 
    		else if (osName.startsWith("Windows")) 
    		{
    			Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + theLink); 
    			return true;
    		}
    		else 
    		{ 
    			//assume Unix or Linux 
    			String[] browsers = { "firefox", "opera", "konqueror", "epiphany", "mozilla", "netscape" }; 
    			String browser = null; 
    			for (int count = 0; count < browsers.length && browser == null; count++) 
    				if (Runtime.getRuntime().exec( new String[] {"which", browsers[count]}).waitFor() == 0) 
    					browser = browsers[count]; 
    			if (browser == null) 
    				return false;
    			else 
    			{
    				Runtime.getRuntime().exec(new String[] {browser, theLink.toString()});
    				return true;
    			}
    		}
    	}
    	catch (Exception e) 
    	{ 	
    		e.toString();
    	}
    	
		return false;
    }
	    
	static public void setApplet ( JApplet inApplet )
	{
		isApplet = true;
		theApplet = inApplet;
	}
	static public boolean isApplet() {return isApplet;} 
	static public void setIsApplet(boolean is) {isApplet = is;}
	static JApplet theApplet = null;
	static boolean isApplet = false;
	
    private UIHelpers () {}; // Don't instantiate
}
